#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parser.h"
#define OK 0
#define NO_MEM 1



/*
PRE: Recibe una variable del tipo Parser y la inicializa.
POS: Devuelve la variable inicializada.
*/
int parser_New(Parser* parser, Parametros* lista_parametros){
  int i;
  parser->tokens=NULL;
  parser->tokensMax=0;
  parser->lista_parametros.cant=lista_parametros->cant;
  parser->lista_parametros.vec_parametros=(char**)malloc(sizeof(char**)*(lista_parametros->cant));
  for (i=0;i<lista_parametros->cant;i++){
    parser->lista_parametros.vec_parametros[i]=(char*)malloc(sizeof(char*)*sizeof(lista_parametros->vec_parametros[i]));
    parser->lista_parametros.vec_parametros[i]=strdup(lista_parametros->vec_parametros[i]);
  }
  return OK;
}

/*
PRE: Recive una lista de parametros sin inicializar.
POS: Inicializa la lista de parametros.
*/
int Crear_lista_parametros (Parametros* lista_parametros){
  lista_parametros->vec_parametros=NULL;
  lista_parametros->cant=0;
  return OK;
}

/*
PRE: recibe un struck del tipo Parametros el cual puede estar inicialisado como no y un parametro a agregar.
POS: Devuelve el struct con el parametro agregado a la lista de parametros e incrementando en uno su cantidad.
*/
int agregar_parametro(Parametros* lista_parametros, char* parametro){
    if (lista_parametros->cant==0){
        lista_parametros->vec_parametros=(char**)malloc(sizeof(char*));
        if (lista_parametros->vec_parametros==NULL){
          fprintf(stderr,"Error: Memoria insuficiente");
          return NO_MEM;
        }
        lista_parametros->vec_parametros[0]=(char*)malloc(sizeof(char)*strlen(parametro));
        if (lista_parametros->vec_parametros[0]==NULL){
          fprintf(stderr,"Error: Memoria insuficiente");
          return NO_MEM;
        }
        lista_parametros->cant++;
        lista_parametros->vec_parametros[0]=strdup(parametro);
        return OK;
    }else{
      lista_parametros->vec_parametros=(char**)realloc(lista_parametros->vec_parametros,sizeof(char*)*(lista_parametros->cant+1));
      if (lista_parametros->vec_parametros==NULL){
          fprintf(stderr,"Error: Memoria insuficiente");
          return NO_MEM;
      }
      lista_parametros->vec_parametros[lista_parametros->cant]=(char*)malloc(sizeof(char)*strlen(parametro));
      if (lista_parametros->vec_parametros[lista_parametros->cant]==NULL){
          fprintf(stderr,"Error: Memoria insuficiente");
          return NO_MEM;
      }
      lista_parametros->vec_parametros[lista_parametros->cant]=strdup(parametro);
      lista_parametros->cant++;
      return OK;
    }
  }

/*Carga un char** con los tokens que estan en parser */
void carga_tokens(Parser parser, char*** tokens  ){
  int i;
  *tokens=NULL;
  *tokens=(char**) malloc(sizeof(char*)* (parser.tokensMax) );
  for(i=0; i< parser.tokensMax; i++ ){
    (*tokens)[ i ]=(char*) malloc(sizeof(char) * (strlen(parser.tokens[ i ])+1) );
    (*tokens)[ i ]=strdup( parser.tokens[ i ] );
  }
}

/*Devuelve la cantidad maxima de tokens*/
int tokensMax (Parser parser ){
    return parser.tokensMax;
}

/*
PRE: Recibe una variable del tipo Parser con la lista de parametros NO VACIA y la linea a parsear.
POS: Devuelve adentro de parser la linea parseada separada por campos, en la lista de tokens y su cantidad.
*/
int Parsear (Parser* parser, void* lineaInput){
  char* linea=(char*)lineaInput;
  int i=0,k=0;
  int j;
  if (parser->tokens!=NULL){
    limpiar_lista_tokens(parser->tokens,parser->tokensMax);
  }
  parser->tokens=(char**)malloc(sizeof(char**));
  parser->tokensMax=0;
  char* buffer=(char*)malloc(sizeof(char)+(strlen(linea)+1));
  char* buffer2=(char*)malloc(sizeof(char)+(strlen(linea)+1));
  int token_actual=0;
  while (linea[i]!='\0'){
    buffer[k]=linea[i];
    buffer[k+1]='\0';
    for (j=0;j<(parser->lista_parametros.cant);j++){
        if (strstr(buffer,parser->lista_parametros.vec_parametros[j] )!=NULL){
          if (strlen(buffer)>strlen(parser->lista_parametros.vec_parametros[j])){
            parser->tokens=(char**)realloc(parser->tokens,sizeof(char**)*
                (token_actual+1));
            parser->tokens[token_actual]=(char*)malloc(sizeof(char*)*
                (k-strlen(parser->lista_parametros.vec_parametros[j])+1));
            buffer2=strdup(buffer);
            buffer2[k+1-strlen(parser->lista_parametros.vec_parametros[j])]='\0';
            parser->tokens[token_actual]=strdup(buffer2);
            parser->tokensMax++;
            token_actual++;
            buffer[0]='\0';
            k=-1;
          }
          parser->tokens=(char**)realloc(parser->tokens,sizeof(char**)*(token_actual+1));
          parser->tokens[token_actual]=(char*)malloc(sizeof(char*)*
            (strlen(parser->lista_parametros.vec_parametros[j])));
          parser->tokens[token_actual]=strdup(parser->lista_parametros.vec_parametros[j]);
          parser->tokensMax++;
          token_actual++;
          buffer[0]='\0';
          k=-1;
        }
    }
    i++;
    k++;
  }
  if (buffer[0]!='\0'){
    parser->tokens=(char**)realloc(parser->tokens,sizeof(char**)*(token_actual+2));
    parser->tokens[token_actual]=(char*)malloc(sizeof(char*)*(strlen(buffer)+1));
    parser->tokens[token_actual]=strdup(buffer);
    parser->tokensMax++;
    token_actual++;
    buffer[0]='\0';
  }
  free (buffer);
  free (buffer2);
  return OK;
}

/*
PRE: Recibe una lista de parametros NO VACIA.
POS: Libera la memoria allocada por esa lista de parametros.
*/
int limpiar_lista_parametros(Parametros* lista_parametros){
  int i;
  for (i=0;i<(lista_parametros->cant);i++){
    if ((lista_parametros->vec_parametros[ i ])!=NULL){
      free(lista_parametros->vec_parametros[ i ]);
    }
   }
  if ((lista_parametros->vec_parametros) !=NULL){
    free(lista_parametros->vec_parametros);
  }
return OK;
}

/*
PRE: Recibe una lista de tokens NO VACIA.
POS: Libera la memoria allocada por esa lista de tokens.
*/
int limpiar_lista_tokens(char** tokens,int tokensMax){
 int i;
  for (i=0;i<tokensMax;i++)
    if (tokens[i]!=NULL){
      free(tokens[i]);
    }
  if (tokens!=NULL)
      free(tokens);
  return OK;
}

/*
PRE: Recibe una variable del tipo Parser, con una lista de tokens y parametros NO VACIAS.
POS: Libera la memoria allocada por esas listas guadadas dentro del parser.
*/
int parser_Destruir(Parser* parser){
  limpiar_lista_parametros(&parser->lista_parametros);
  limpiar_lista_tokens(parser->tokens,parser->tokensMax);
  return OK;
  }



